# waveplugs/watcher.py
#
#

""" watch waves through xmpp. a wave is called a channel here. """

## gozerlib imports

from gozerlib.commands import cmnds
from gozerlib.callbacks import callbacks
from gozerlib.persist.persist import PlugPersist
from gozerlib.gozernet.bot import GozerNetBot
from gozerlib.wave.bot import WaveBot

## basic imports

import copy
import logging

cpy = copy.deepcopy

class Watched(PlugPersist):

    """ Watched object contains channels and subscribers. """

    def __init__(self, filename):
        PlugPersist.__init__(self, filename)
        self.data.channels = self.data.channels or {}
        self.data.whitelist = self.data.whitelist or []
        self.data.descriptions = self.data.descriptions or {}

    def subscribe(self, botname, channel, jid):

        """ subscrive a jid to a channel. """ 

        if not self.available:
            return False

        jid = unicode(jid)

        if not self.data.channels.has_key(channel):
            self.data.channels[channel] = []

        if not [botname, jid] in self.data.channels[channel]:
            self.data.channels[channel].append([botname, jid])
            self.save()

        return True

    def unsubscribe(self, botname, channel, jid):

        """ unsubscribe a jid from a channel. """ 

        try:
            self.data.channels[channel].remove([botname, unicode(jid)])

        except (KeyError, TypeError):
            return False

        self.save()
        return True

    def check(self, channel):

        """ check if channel is available (in whitelist) AND has subscribers. """

        return self.data.channels.has_key(channel)

    def subscribers(self, channel):

        """ return all subscribers of a channel. """

        try:
            return self.data.channels[channel]
        except KeyError:
            return None

    def enable(self, channel):

        """ add channel to whitelist. """

        if not channel in self.data.whitelist:
            self.data.whitelist.append(channel)
            self.save()

    def disable(self, channel):
 
        """ remove channel from whitelist. """

        try:
            self.data.whitelist.remove(channel)
        except ValueError:
            return False

        self.save()
        return True

    def available(self, channel):

        """ check if channel is on whitelist. """

        return channel in self.data.whitelist

    def channels(self):

        """ return channels on whitelist. """

        return self.data.channels.keys()

watched = Watched('channels')
outbot = GozerNetBot('watch')
wavebot = WaveBot('watchwave')

def prewatchcallback(bot, event):

    return watched.check(event.channel) and event.txt

def watchcallback(bot, event):

    subscribers = watched.subscribers(event.channel)
    watched.data.descriptions[event.channel] = event.title
    logging.debug("watcher - out - %s - %s" % (str(subscribers), event.txt))

    for item in subscribers:
        try:
            (botname, channel) = item
        except ValueError:
            continue

        if 'wave' in botname:
            wavebot.say(channel, u"<%s> %s" % (event.nick or event.userhost, event.txt))
        else:
            outbot.say(channel, u"<%s> %s" % (event.nick or event.userhost, event.txt))

callbacks.add('BLIP_SUBMITTED', watchcallback, prewatchcallback)
callbacks.add('PRIVMSG', watchcallback, prewatchcallback)

def handle_watcherstart(bot, event):

    if not event.rest:
        event.missing('<channel>')
        return

    watched.subscribe(bot.name, event.rest, event.channel)
    event.done()

cmnds.add('watcher-start', handle_watcherstart, 'USER')

def handle_watcherstop(bot, event):

    if not event.rest:
        event.missing('<channel>')
        return

    watched.unsubscribe(bot.name, event.rest, event.userhost)
    event.done()

cmnds.add('watcher-stop', handle_watcherstop, 'USER')

def handle_watcherlist(bot, event):
    chans = watched.channels()

    if chans:
        res = []

        for chan in chans: 

            try:
                res.append("%s (%s)" % (chan, watched.data.descriptions[chan]))
            except KeyError:
                res.append(chan)

        event.reply("available channels: ", res)

cmnds.add('watcher-list', handle_watcherlist, ['USER'])
